package com.example.elastcisearch;

import lombok.SneakyThrows;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Before;
import org.junit.Test;

public class TestSearch {
    private RestHighLevelClient client = null;

    @Before
    public void before() {
        RestClientBuilder builder = RestClient.builder(new HttpHost("192.168.228.104", 9200, "http"));
        client = new RestHighLevelClient(builder);
    }



    @Test
    @SneakyThrows
    public void searchTerm() {
        SearchRequest request = new SearchRequest("order");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.termQuery("orderNo", "1564554455445"));
        //in: builder.query(QueryBuilders.termsQuery("orderNo", "1564554455445", ""));
        builder.from(0);
        builder.size(10);

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }



    @Test
    @SneakyThrows
    public void searchAll() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchAllQuery());
        builder.from(0);
        builder.size(10);
        
        String[] includes = {"name", "desc", "keyword"};
        builder.fetchSource(includes, null);
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }

    @Test
    @SneakyThrows
    public void ids() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.idsQuery().addIds("6VeVQHIBLRcCVC1FBdum"));
        
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }

    @Test
    @SneakyThrows
    public void matchQuery() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        
        builder.query(QueryBuilders.matchQuery("keyword", "php"));

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }


    @Test
    @SneakyThrows
    public void multiMatchQuery() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();

        String[] fields = {"keyword", "desc"};
        builder.query(QueryBuilders.multiMatchQuery("php", fields));

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }


    /**
     * GET /order/_search
     * {
     *   "query": {
     *     "prefix": {
     *       "orderNo": {
     *         "value": "156"
     *       }
     *     }
     *   }
     * }
     */
    @Test
    @SneakyThrows
    public void prefixQuery() {
        SearchRequest request = new SearchRequest("order");
        SearchSourceBuilder builder = new SearchSourceBuilder();

        builder.query(QueryBuilders.prefixQuery("orderNo", "156"));

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }

    /**
     * 模糊查询：输入错误也能匹配搜索但是前prefix_length个不能错
     * GET /order/_search
     * {
     *   "query": {
     *     "fuzzy": {
     *       "hobby": {
     *         "value": "乱",
     *         "prefix_length": 3
     *       }
     *     }
     *   }
     * }
     */
    @Test
    @SneakyThrows
    public void fuzzyQuery() {
        SearchRequest request = new SearchRequest("order");
        SearchSourceBuilder builder = new SearchSourceBuilder();

        builder.query(QueryBuilders.fuzzyQuery("hobby", "乱七八糟的").prefixLength(3));

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }


    /** 允许 * ?的通配符模糊查询
     *
     * GET /order/_search
     * {
     *   "query": {
     *     "wildcard": {
     *       "hobby": {
     *         "value": "*乱*"
     *       }
     *     }
     *   }
     * }
     */
    @Test
    @SneakyThrows
    public void wildcardQuery() {
        SearchRequest request = new SearchRequest("order");
        SearchSourceBuilder builder = new SearchSourceBuilder();

        builder.query(QueryBuilders.wildcardQuery("hobby", "乱**"));

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }




















/*
    GET /shop/_search
    {
        "query":{
        "bool":{
            "must":[{
                "match":{
                    "name":"jack"
                }
            }
			],
            "should":[{
                "match":{
                    "content":"tgrgreg"
                }
            }
			],
            "must_not":[{
                "match":{
                    "desc":"hello"
                }

            }]


            }
        }
     }
    */
    @Test
    @SneakyThrows
    public void bool() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        
        String[] fields = {"keyword", "desc"};
        queryBuilder.must(QueryBuilders.multiMatchQuery("php", fields));
        queryBuilder.should(QueryBuilders.matchQuery("desc", "java"));
        queryBuilder.mustNot(QueryBuilders.matchQuery("desc", "java"));
        
        builder.query(queryBuilder);

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }

    /**
     *
     */
    @Test
    @SneakyThrows
    public void scroll() {
        SearchRequest request = new SearchRequest("order");
        request.scroll(TimeValue.timeValueMinutes(1));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(QueryBuilders.matchAllQuery());
        builder.size(3);
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        String scrollId = response.getScrollId();
        System.out.println(scrollId);
        for (SearchHit hit : response.getHits()) {
            System.out.println(hit.getSourceAsMap());
        }
        while (true) {
            SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId);
            scrollRequest.scroll(TimeValue.timeValueMinutes(1));
            SearchResponse searchResponse = client.scroll(scrollRequest, RequestOptions.DEFAULT);
            SearchHits hits = searchResponse.getHits();
            if (hits.getHits().length > 0) {
                for (SearchHit hit : hits) {
                    System.out.println(hit.getSourceAsMap());
                }
            } else {
                break;
            }
        }
        ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
        clearScrollRequest.addScrollId(scrollId);
        client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
    }


    @Test
    @SneakyThrows
    public void rangeQuery() {
        SearchRequest request = new SearchRequest("index2");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        
        queryBuilder.filter(QueryBuilders.rangeQuery("age").gte(23).lte(34));

        builder.query(queryBuilder);
        builder.sort("age", SortOrder.ASC);

        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            System.out.println(searchHit.getId());
            System.out.println(searchHit.getScore());
            System.out.println(searchHit.getIndex());
            System.out.println(searchHit.getSourceAsMap());
            System.out.println("****************");
        }
    }


    /**
     * # 匹配了positive 又匹配了negative ，降低分数
     * POST /shop/_search
     * {
     *   "query": {
     *     "boosting": {
     *       "positive": {
     *         "match": {
     *           "name": "phone"
     *         }
     *       },
     *       "negative": {
     *         "match": {
     *           "desc": "小笼包"
     *         }
     *       },
     *       "negative_boost": 0.5
     *     }
     *   }
     * }
     */
    @Test
    @SneakyThrows
    public void boostingQuery() {
        SearchRequest request = new SearchRequest("shop");
        SearchSourceBuilder builder = new SearchSourceBuilder();
        BoostingQueryBuilder boostingQueryBuilder = QueryBuilders.boostingQuery(
                QueryBuilders.matchQuery("name", "phone"),
                QueryBuilders.matchQuery("desc", "小笼包")
        ).negativeBoost(0.5F);
        builder.query(boostingQueryBuilder);
        request.source(builder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        for (SearchHit hit : response.getHits()) {
            System.out.println(hit.getSourceAsMap());
        }
    }

















}
